/**
 + (id<AspectToken>)aspect_hookSelector:(SEL)selector
 withOptions:(AspectOptions)options
 usingBlock:(id)block
 error:(NSError **)error;
 1、aspect_hookSelector:表示要拦截指定对象的方法。
 2、withOptions:是一个枚举类型，AspectPositionAfter表示viewDidLoad方法执行后会触发usingBlock:的代码。
 3、usingBlock:就是拦截事件后执行的自定义方法。我们可以在这个block里面添加我们要执行的代码。
 */

//【计算事件】 用于统计数值型变量的累计值、均值及分布。
//【计数事件】 用于统计字符串型变量的消息数及触发设备数。


//
//  AppDelegate+AopUMStatistical.m
//  GuaWaProject
//  友盟appkey：5a309ff7b27b0a7993000060
//  Created by chenzm on 2018/8/28.
//  Copyright © 2018年 木炎. All rights reserved.
//

#import "AppDelegate+AopUMStatistical.h"
#import <Aspects.h>
#import <objc/runtime.h>
//友盟
#import <UMCommon/UMCommon.h>
#import <UMAnalytics/MobClick.h>
///事件统计工具
#import "ZMMobClickTool.h"

//方法名称
#define kEventName @"EventName"
//事件id
#define kEventId @"EventId"
//返回字典参数键值的数组
#define kParams @"Params"

//【必填】统计事件类型 1、点击事件 2、开始事件 3、结束事件
#define kEventType @"kEventType"
//【必填】接口参数个数：0、无参数返回 1、返回一个参数 2、返回两个参数 3或其他：【自定义】
#define kAspParamsCount @"kAspParamsCount"
//【可不填】分类标签,不同的标签会分别进行统计
#define kLblTypeStr @"kLblTypeStr"


//---- 页面处理 ----
//游戏房间充值
static NSString *page_RechargePlay = @"RechargePlay";
//首页充值
static NSString *page_RechargeMain = @"RechargeMain";

//充值事件
static NSString *event_RechargePlay = @"event_RechargePlay";
static NSString *event_RechargeMain = @"event_RechargeMain";

#define AopUserfaults [NSUserDefaults standardUserDefaults]
@implementation AppDelegate (AopUMStatistical)

///配置基本信息
- (void)configureUMTrack{
    //初始化友盟所有组件产品
    [UMConfigure initWithAppkey:@"友盟appkey" channel:@"App Store"];
    ///对统计信息进行加密传输
    [UMConfigure setEncryptEnabled:YES];
    
    //bug统计处理
    [MobClick setScenarioType:E_UM_NORMAL|E_UM_DPLUS];//设置 统计场景类型
    [MobClick setCrashReportEnabled:YES];//开启CrashReport收集
}

///设置事件分析
- (void)setUpAnalytics{
    //访问路径
    [self setUpUMEventAnalytics];
    //埋点事件分析
    [self setUpUMUIAnalytics];
}


/// 设置页面访问路径
-(void)setUpUMUIAnalytics{
    [self setPageStaticByBaseVC];
}

///基础控制器页面统计
-(void)setPageStaticByBaseVC{
    NSString *_msgStr = [self getAnalyMsg];
    if (AnaIsEmptyStr(_msgStr)) {
        _msgStr = @"";
    }
    
    //所有页面路径
    [self aspectBaseVC];
    
    //将事件做页面路径特殊处理（充值事件）
    [self aspectRechargePage:_msgStr];
}

#pragma mark - 页面路径
///所有页面访问路径
-(void)aspectBaseVC{
    __weak typeof(self) weakSelf = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //获取页面统计路径列表
        NSDictionary *pageDict = [weakSelf getPlistWithName:@"UMPageStatisticsList"];
        NSArray *_keysArr = pageDict.allKeys;
        
        //基类控制器页面：UIViewController或者自定义的基类
        Class baseClass = NSClassFromString(@"UIViewController");
        
        
        [baseClass aspect_hookSelector:@selector(viewWillAppear:) withOptions:AspectPositionAfter usingBlock:^(id <AspectInfo> aspectInfo, BOOL animated){
            [weakSelf responsePageStatics:aspectInfo keysArr:_keysArr pageType:1];
        } error:NULL];
        
        [baseClass aspect_hookSelector:@selector(viewWillDisappear:) withOptions:AspectPositionAfter usingBlock:^(id <AspectInfo> aspectInfo, BOOL animated){
            [weakSelf responsePageStatics:aspectInfo keysArr:_keysArr pageType:2];
        } error:NULL];
        
        [baseClass aspect_hookSelector:NSSelectorFromString(@"dealloc") withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo>aspectInfo){
            //        NSLog(@"\nDealloc:%@",[aspectInfo.instance class]);
        } error:NULL];
    });
}


///充值页面监测及事件监听
-(void)aspectRechargePage:(NSString *)msgStr{
    NSString *_analyMsgStr = msgStr;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //游戏页面
        Class playVC = NSClassFromString(@"文件类");
        //首页
        Class mainVC = NSClassFromString(@"文件类");
        SEL action = NSSelectorFromString(@"btnRechargeAction:");
        [playVC aspect_hookSelector:action withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo>aspectInfo,UIButton *btn){
            [AopUserfaults setInteger:1 forKey:@"Recharge"];
            [ZMMobClickTool zm_beginLogPageView:page_RechargePlay];
            
            [ZMMobClickTool zm_beginEventId:event_RechargePlay dic:@{event_RechargePlay:_analyMsgStr} lblStr:nil];
        } error:NULL];
        
        [mainVC aspect_hookSelector:action withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo>aspectInfo,UIButton *btn){
            [AopUserfaults setInteger:2 forKey:@"Recharge"];
            [ZMMobClickTool zm_beginLogPageView:page_RechargeMain];
            [ZMMobClickTool zm_beginEventId:event_RechargeMain dic:@{event_RechargeMain:_analyMsgStr} lblStr:nil];
        } error:NULL];
        
        SEL action1 = NSSelectorFromString(@"addPayNotifition");
        [AppDelegate aspect_hookSelector:action1 withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo>aspectInfo){
            
            NSInteger rechargeFrom = [AopUserfaults integerForKey:@"Recharge"];
            if (rechargeFrom == 1) {
                [ZMMobClickTool zm_endLogPageView:page_RechargePlay];
                [ZMMobClickTool zm_endEventId:event_RechargePlay dic:@{event_RechargePlay:_analyMsgStr} lblStr:nil];
            }else if (rechargeFrom == 2){
                [ZMMobClickTool zm_endLogPageView:page_RechargeMain];
                [ZMMobClickTool zm_endEventId:event_RechargeMain dic:@{event_RechargeMain:_analyMsgStr} lblStr:nil];
            }
            
            [AopUserfaults removeObjectForKey:@"Recharge"];
            [AopUserfaults synchronize];
        } error:NULL];
        
        
        // ---- 页面统计 ----
        SEL action2 = NSSelectorFromString(@"doCoin");
        [playVC aspect_hookSelector:action2 withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo>aspectInfo){
            [ZMMobClickTool zm_beginLogPageView:@"ClickDoCoin"];
        } error:NULL];
        
        SEL action3 = NSSelectorFromString(@"doCoinSuccess");
        [playVC aspect_hookSelector:action3 withOptions:AspectPositionAfter usingBlock:^(id<AspectInfo>aspectInfo){
            [ZMMobClickTool zm_endLogPageView:@"ClickDoCoin"];
        } error:NULL];

    });
}

/**
 切片页面统计反馈处理
 @param aspectInfo 返回信息
 @param keysArr 键值数组
 @param pageType 页面类型
 */
-(void)responsePageStatics:(id <AspectInfo>)aspectInfo keysArr:(NSArray *)keysArr pageType:(NSInteger)pageType{
    NSString *pageName = NSStringFromClass([aspectInfo.instance class]);
    //如果要做页面的选择性上传，可以使用该判断处理
//    if ([keysArr containsObject:pageName]) {
        if (!AnaIsEmptyStr(pageName)) {
            switch (pageType) {
                case 1:{//进入
                    [ZMMobClickTool zm_beginLogPageView:pageName];
                }break;
                case 2:{//离开
                    [ZMMobClickTool zm_endLogPageView:pageName];

                }break;
                default:
                    break;
            }
        }
//    }
}

#pragma mark - 事件处理

///设置友盟统计
-(void)setUpUMEventAnalytics{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        //获取需要统计的事件列表
        NSDictionary *eventStatisticsDict = [self getPlistWithName:@"UMEventStatisticsList"];
        
        for (NSString *classNameStr in eventStatisticsDict.allKeys) {
            //使用运行时创建对象
            const char *className = [classNameStr UTF8String];
            //从一个字串返回一个类
            Class newClass = objc_getClass(className);
            
            NSArray *pageEventList = [eventStatisticsDict objectForKey:classNameStr];
            for (NSDictionary *eventDict in pageEventList) {
                //事件方法名称
                NSString *eventMethodName = eventDict[kEventName];
                SEL selector = NSSelectorFromString(eventMethodName);
                
                NSString *eventId = eventDict[kEventId];
                NSArray *params = eventDict[kParams];
                
                NSInteger aspectType = [eventDict[kAspParamsCount] integerValue];
                NSInteger eventType = [eventDict[kEventType] integerValue];
                NSString *labelStr = eventDict[kLblTypeStr];
                [self trackEventWithClass:newClass selector:selector eventId:eventId params:params aspectType:aspectType eventType:eventType cateLabelStr:labelStr];
            }
        }
    });
}


/**
 设置事件统计
 @param class 类目
 @param selector 方法
 @param eventId 事件id
 @param paramNames 参数数组
 @param aspectType 切片返回参数数量
 @param eventType 上传事件类型
 @param lblStr 分类标签
 */
- (void)trackEventWithClass:(Class)class selector:(SEL)selector eventId:(NSString *)eventId params:(NSArray *)paramNames aspectType:(NSInteger)aspectType eventType:(NSInteger)eventType cateLabelStr:(NSString *)lblStr{
    
    __weak typeof (self) weakSelf = self;
    switch (aspectType) {
        case 0:{
            [class aspect_hookSelector:selector withOptions:AspectPositionAfter usingBlock:^(id <AspectInfo> aspectInfo){
                if (aspectInfo) {
                    NSDictionary *dic = [weakSelf responseAspectEventId:eventId params:paramNames eventType:eventType obj:nil];
                    [weakSelf umEventWithEventId:eventId dic:dic lblStr:lblStr eventType:eventType];
                }
            } error:NULL];
        }break;
        case 1:{
            //放到异步线程去执行
            [class aspect_hookSelector:selector withOptions:AspectPositionAfter usingBlock:^(id <AspectInfo> aspectInfo,id obj){
                NSDictionary *dic = [weakSelf responseAspectEventId:eventId params:paramNames eventType:eventType obj:obj];
                [weakSelf umEventWithEventId:eventId dic:dic lblStr:lblStr eventType:eventType];
            } error:NULL];
        }break;
        case 2:{
            [class aspect_hookSelector:selector withOptions:AspectPositionAfter usingBlock:^(id <AspectInfo> aspectInfo,id obj1,id obj2){
                NSLog(@"\nobj1=%@,obj2=%@",obj1,obj2);
            } error:NULL];
        }break;
        default:{
            
        }break;
    }
}

/**
 切片事件返回处理
 @param eventId 事件id
 @param params 参数数组
 @param eventType 上传事件类型
 @param obj 返回值
 */
-(NSDictionary *)responseAspectEventId:(NSString *)eventId params:(NSArray *)params eventType:(NSInteger)eventType obj:(id)obj{
    ///可变字符串
    NSMutableString *appendString = [[NSMutableString alloc] initWithCapacity:0];
    
    ///事件必传的基本信息
    NSString *userInfoStr = [self getAnalyMsg];
    if (!AnaIsEmptyStr(userInfoStr)) {
        [appendString appendFormat:@"%@", userInfoStr];
    }
    if (obj) {
        if ([obj isKindOfClass:[NSDictionary class]]
            ||[obj isKindOfClass:[NSMutableDictionary class]]) {
            NSDictionary *dict = (NSDictionary *)obj;
            
            //如果有参数，那么把参数名和参数值拼接在eventID之后
            if (params.count > 0) {
                if ([dict isKindOfClass:[NSDictionary class]]) {
                    //获取dict
                    for (NSString *paramName in params) {
                        NSString *paramValue = [dict objectForKey:paramName];
                        [appendString appendFormat:@"%@=%@,", paramName, paramValue];
                    }
                }
            }
        }else if ([obj isKindOfClass:[NSArray class]]||[obj isKindOfClass:[NSMutableArray class]]){
            NSArray *arr = (NSArray *)obj;
            if (arr&&arr.count > 0) {
                //            appendString = [[NSMutableString alloc] initWithCapacity:0];
                for (NSInteger i = 0; i < arr.count; i++) {
                    NSString *str = arr[i];
                    if (str&&str.length > 0) {
                        [appendString appendString:[NSString stringWithFormat:@"%@,",str]];
                    }
                }
            }
        }else if ([obj isKindOfClass:[NSString class]]||[obj isKindOfClass:[NSMutableString class]]){
            NSString *str = (NSString *)obj;
            if (str&&str.length > 0) {
                [appendString appendFormat:@"%@", str];
            }
        }else{
            NSLog(@"\neventObj:%@",obj);
        }
    }else{
        //方法没有参数
    }
    NSDictionary *dic = nil;
    if (appendString&&appendString.length > 0) {
        dic =@{eventId:appendString};
    }
    
    return dic;
}

/**
 提交事件统计
 @param eventId 事件id
 @param dic 上传的参数
 @param lblStr 分类标签
 @param eventType 事件类型
 */
-(void)umEventWithEventId:(NSString *)eventId dic:(NSDictionary *)dic lblStr:(NSString *)lblStr eventType:(NSInteger)eventType{
    //统计事件类型1、点击事件 2、开始事件 3、结束事件
    switch (eventType) {
        case 1:{
            [ZMMobClickTool zm_countEventId:eventId dic:dic lblStr:lblStr];
        }break;
        case 2:{
            [ZMMobClickTool zm_beginEventId:eventId dic:dic lblStr:lblStr];
        }break;
        case 3:{
            [ZMMobClickTool zm_endEventId:eventId dic:dic lblStr:lblStr];
        }break;
        default:
            break;
    }
}


///获取plist列表数据
-(NSDictionary *)getPlistWithName:(NSString *)plistName{
    if (plistName) {
        NSString *path = [[NSBundle mainBundle]pathForResource:plistName ofType:@"plist"];
        NSDictionary *pageDict = [[NSDictionary alloc]initWithContentsOfFile:path];
        return pageDict;
    }else{
        return nil;
    }
}

#pragma mark - 自定义
///获取统计用户基本信息
static NSString *_appendStr;
-(NSString *)getAnalyMsg{
    return @"要上传备注的信息";
    
}


@end
